/*
 *	CHANGE LOG
 * 
 * 01.02.02
 *
 *		12/27/2008 - DW - Added code to authorize user for method calls
 *
 * 01.02.03
 *
 *		07/09/2009 - DW - Added support for workflow and versioning added to DNN 5.1
 * 
 * 01.02.04
 * 
 *      11/11/2009 - DW - Updated the GetRecentItems method to return all the items if 
 *                          the numberOfItems = 20 or 500 or more.
 */


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Entities.Users;
using DotNetNuke.Modules.Html;
using DotNetNuke.Security;
using MetaPostProvider.TextHtml;
using DataProvider=DotNetNuke.Data.DataProvider;

namespace ITCrossing
{
	public class metaPostTextHtmlProvider : IPublishable
	{
		# region IPublishable Members

		# region Public Properties
		
		/// <summary>
		/// ProviderKey should be set to the Friendly Name of the module for
		/// which this provider is being implemented.
		/// </summary>
		public string ProviderKey
		{
			get
			{
				return MetaPostServices.GetFriendlyNameFromModuleDefinition("Text/HTML");
			}
		}
		
		/// <summary>
		/// ManifestFilePath is the path including the filename to the manifest file used to determine 
		/// the settings available in Windows Live Writer.  An example path might
		/// be /DesktopModules/itcMetaPost/manifests/wlwblog.xml.  See the following URL for 
		/// information regarding what Content can be placed in a WLW manifest file:
		/// http://msdn2.microsoft.com/en-us/library/bb463260.aspx
		/// </summary>
		public string ManifestFilePath
		{
			get { return "/DesktopModules/itcMetaPost/manifests/wlwtexthtml.xml"; }
		}
		
		/// <summary>
		/// LocalizationFilePath is the path including the filename to the 
		/// resource file used by metaPost to retrieve the error messages
		/// shown to the user (eg. "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPost")
		/// </summary>
		public string LocalizationFilePath
		{
			get { return "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPostTextHtml"; }
		}
		
		/// <summary>
		/// OPTIONAL - ImageUploadPath is a property metaPost uses to determine where 
		/// to store the media files (images).  This property should return just a 
		/// section of the path starting from the portal root.  Added to this path will
		/// be the username along with the path 
		/// </summary>
		public string ImageUploadPath
		{
			get
			{
				// This can be overridden with custom implementation if needed.  If
				// overridden, then a message should be placed in the ImagePath column
				// for your provider letting administrators know that administration of
				// the ImagePath is implemented elsewhere.  
				return MetaPostServices.GetProviderImageUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// AttachmentUploadPath is used to specify the location of attachments added
		/// to a post or page.
		/// </summary>
		public string AttachmentUploadPath
		{
			get
			{
				// For now, we'll just set this to the same as the image upload path
				return MetaPostServices.GetProviderAttachmentUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// SettingsUserControlPath is for future use.  It will return the path to the
		/// the settings user control for this provider.  
		/// </summary>
		public string SettingsUserControlPath
		{
			get { throw new NotImplementedException(); }
		}

		/// <summary>
		/// FooterScriptIncludePath determines the path to the JavaScript file which 
		/// inserts the AddThis and other widgets to the bottom of a post.  This property
		/// is not a part of the IPublishable interface, but metaPost will look to see if 
		/// it exists through reflection and use the value returned if the provider
		/// implements a property named FooterScriptIncludePath.
		/// </summary>
		public string FooterScriptIncludePath
		{
			get { return "/DesktopModules/itcMetaPost/js/mg.js?://"; }
		}
		# endregion

		# region Get Methods

		/// <summary>
		/// The purpose of this procedure is to provide a list of all the modules in a 
		/// given portal to which the currently logged on user has either insert, update
		/// or delete access.  Note, this may not always correspond to an actual module.
		/// For example, with the DNN Blog module provider, a list of blogs is returned
		/// along with URL of where each blog is available within the site.  For the News
		/// Articles module, we return a list of all News Articles modules that have been
		/// added to Tabs throughout the site.
		/// </summary>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		/// <param name="providerKey"></param>
		public ModuleInfoStruct[] GetModulesForUser(UserInfo userInfo, PortalSettings portalSettings, string providerKey)
		{
			ModuleInfoStruct[] infoArray = new ModuleInfoStruct[1];

			ModuleInfoStruct moduleInfo = new ModuleInfoStruct();
			moduleInfo.ModuleLevelId = portalSettings.PortalId.ToString();
			moduleInfo.ModuleName = portalSettings.PortalName;
			moduleInfo.Url = MetaPostServices.GetRedirectUrl(providerKey, portalSettings.HomeTabId); 

			infoArray[0] = moduleInfo;

			return infoArray;
		}

		/// <summary>
		/// GetRecentItems returns a list of the recent items added to the module.  For example, with
		/// the blog module, the list would return all the recent blog entries.  For the Text/HTML provider, 
		/// this method would return a list of the recently added Text/HTML modules in the site.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="numberOfItems"></param>
		/// <param name="requestType">GetRecentItems can be called for a number of reasons.  In Windows Live Writer,
		/// users are able to retrieve a list of recent posts or recent pages.  The requestType parameter is used
		/// to denote whether a list of pages or posts is being requested.  Additionally, WLW may request a list 
		/// of hiearchical pages to show pages when allowing a parent page to be assigned to a new page.  The values for this enum
		/// are RecentPosts, RecentPages and RecentPagesHiearchical.</param>
		/// <param name="providerKey"></param>
		/// <returns></returns>
		public Item[] GetRecentItems(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, int numberOfItems, RecentItemsRequestType requestType, string providerKey)
		{

			// Make sure user is authorized to call method
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, portalSettings.PortalId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			


			List<Item> itemArray = new List<Item>();

			// List used to retrieve an array of ModuleInfoStructs to return to metaPost.
			List<ModuleInfoStruct> moduleInfoList = new List<ModuleInfoStruct>();

			// dnnModuleInfos is the list which stores the DnnModuleInfoStructs returned from 
			// GetModulesByProviderKeyUserIdAndPortalId.
			List<DnnModuleInfoStruct> dnnModuleInfos
				= MetaPostServices.GetEditableModules(providerKey, userInfo.UserID, portalSettings.PortalId);

            // DW - 11/09/2009 - Updated so all entries can be seen from inside Word 2007.
			if (numberOfItems >= 500 || numberOfItems == 20) numberOfItems = int.MaxValue;

			if (dnnModuleInfos.Count > 0)
			{
				int itemCount = 0;
				foreach (DnnModuleInfoStruct dnnModuleInfo in dnnModuleInfos)
				{
					Item item = new Item();
					item.ItemId = dnnModuleInfo.ModuleId.ToString();
					string modulePath = dnnModuleInfo.TabPath.Replace("//", "/");
					// remove the beginning forward slash
					if (modulePath.Length > 1 && modulePath.Substring(0, 1) == "/")
						modulePath = modulePath.Substring(1);
					item.Title = dnnModuleInfo.ModuleTitle; // +" (" + modulePath + ")";
					item.Content = modulePath;
					item.DateCreated = dnnModuleInfo.CreatedDate;
					// Configure the URL that WLW uses to send the user to after a post has been made
					// We will make use of MetaPostRedirect here to 
					item.Link = Globals.NavigateURL(dnnModuleInfo.TabId);
					itemArray.Add(item);
					itemCount++;
					if (itemCount >= numberOfItems) break;
				}
			}
			else
			{
				throw new MetaPostException("NoModulesForUser",
											"There are no News Article modules associated with this user account.  Please enter a user account which has been associated with a blog.");
			}

			return itemArray.ToArray();
		}

		/// <summary>
		/// GetItem is used to retrieve a specific item, which may be a page or a post if your module supports
		/// both concepts.  In cases where a module supports both pages and posts, a concept made available in 
		/// Windows Live Writer, but not in Word 2007 or in many other publishing clients, the itemType parameter 
		/// can be used to distinguish between when this method is being called to add a page or a post.  If your 
		/// provider doesn't support a distinction between pages and posts, then simply ignore the itemType parameter.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public Item GetItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{

			// Make sure user is authorized to call method
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, portalSettings.PortalId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			Item item = new Item();

			// We will use the stored procedures directly since the Text/HTML controller is in 
			// the App_Code directory of DNN and is not available through a DLL that can be referenced.

			int moduleId = Convert.ToInt32(itemId);

			ProviderStructs.HtmlInfoStruct htmlInfo = new ProviderStructs.HtmlInfoStruct();

			htmlInfo = GetHtmlText(moduleId);

			item.Title = HttpUtility.HtmlDecode(htmlInfo.Title) ?? "";
			item.Content = HttpUtility.HtmlDecode(htmlInfo.DesktopHtml);
			item.Summary = HttpUtility.HtmlDecode(htmlInfo.DesktopSummary);
			item.DateCreated = htmlInfo.CreatedDate;
			item.ItemId = moduleId;

			// Use the UserController to look up a user's name
			UserController userController = new UserController();
			UserInfo dnnUserInfo = userController.GetUser(portalSettings.PortalId, htmlInfo.CreatedByUser);

			item.AuthorId = (dnnUserInfo == null) ? string.Empty : dnnUserInfo.DisplayName;

			item.Content = Globals.ManageUploadDirectory(item.Content, portalSettings.HomeDirectory);

			// We will place the summary in the excerpt field.  No need to find and replace as is the case
			// when the summary is placed in the extended content area.
			//FindAndPlaceSummary(ref item);

			return item;
		}

		# endregion

		# region Add, Edit and Delete Methods

		/// <summary>
		/// NewItem is used for creating new items (either pages or posts).  The implementation 
		/// in your provider can distinguish between page and post requests for NewItem by the 
		/// ItemType property of the Item struct.  Additional properties of the Item Struct which 
		/// may be of interest in the implmentation of this method are: Publish, StyleDetectionPost,StyleId, and ItemType.
		/// See the comments associated with each of these properties of the Item struct for more information.
		/// </summary>
		/// <param name="moduleLevelId">String - ModuleId is a very loose concept here.  Anything can be tracked in this variable as long as it is consistent.  For the Blog module, the BlogId is passed and for the Text/HTML module, the ModuleId is passed and for the Ventrian News Articles module, the ArticleId is passed.  This value is based on the value sent to Windows Live Writer when GetModulesForUser is called. </param>
		/// <param name="userInfo">DotNetNuke UserInfo object.  This UserInfo object is retrieved by metaPost and made available to every method call in the MetaPostProvider interface.</param>
		/// <param name="portalSettings">DotNetNuke PortaSettings object - This is provided to make it easier to work with metaPost.  metaPost does all the work behind the scenes of identifying the right portalSettings object based on the requested URL.</param>
		/// <param name="item">Custom Struct - The item struct contains a list of fields sent through the MetaWeblog API.  The properties have been renamed to make sense in more general applications outside of just blogs.</param>
		/// <returns></returns>
		public string NewItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			// Authorize this attempt to create a new item
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
										   GetModulesForUser(userInfo, portalSettings, ProviderKey));

			
			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			string newId = string.Empty;

			if (item.StyleDetectionPost)
			{
				try
				{
					// Retrieve the HtmlInfoStruct which is basically our own Info object that we
					// implemented as a struct to make it nice and lite.
					ProviderStructs.HtmlInfoStruct htmlInfo = GetHtmlText(Convert.ToInt32(item.StyleId));
					string content = htmlInfo.DesktopHtml;
					string title = htmlInfo.Title;

					// Next, we temporarily store the value in the database.
					MetaPostServices.SetTempStyleValue(userInfo.UserID, "styleId", item.StyleId);
					MetaPostServices.SetTempStyleValue(userInfo.UserID, "content", content);
					MetaPostServices.SetTempStyleValue(userInfo.UserID, "title", title);


					
					// We check to see if we need to add a new entry.  This is the case when the user
					// has created a Text/HTML tabmodule and hasn't added any text to it yet.
					if (string.IsNullOrEmpty(htmlInfo.DesktopHtml))
					{
						AddHtmlText(Convert.ToInt32(item.StyleId), HttpUtility.HtmlEncode(item.Content),
								   HttpUtility.HtmlEncode(item.Summary), userInfo.UserID, item.Publish, portalSettings.PortalId);
						UpdateHtmlText(Convert.ToInt32(item.StyleId), item.Title, HttpUtility.HtmlEncode(item.Content),
                                    HttpUtility.HtmlEncode(item.Summary), userInfo.UserID, item.Publish, portalSettings.PortalId);
					}
					else
					{
						UpdateHtmlText(Convert.ToInt32(item.StyleId), item.Title, HttpUtility.HtmlEncode(item.Content),
                                       HttpUtility.HtmlEncode(item.Summary), userInfo.UserID, item.Publish, portalSettings.PortalId);
					}


					ModuleController moduleController = new ModuleController();
					ModuleInfo moduleInfo = moduleController.GetModule(htmlInfo.ModuleId, Null.NullInteger, false);
					// We set a TempInstallUrl since this is used by metaPost to redirect to the right
					// page when performing style detection.
					MetaPostServices.SetTempInstallUrl(ProviderKey, Globals.NavigateURL(moduleInfo.TabID));

					// Refresh the cache
					MetaPostServices.RefreshCache(moduleInfo, moduleController);

					newId = item.StyleId;

				} catch
				{
					// No problem if we fail, the template just won't be available.
				}
			}
			else
			{
				throw new MetaPostException("FeatureNotImplemented", "This feature is currently not implemented.");
			}

			MetaPostServices.SaveItemImages(Convert.ToInt32(newId), images, ProviderKey, portalSettings, userInfo.UserID);

			return newId;
		}

		/// <summary>
		/// EditItem is called to edit either a page or a post.  The difference
		/// between the two is denoted in a property of the Item struct (ItemType).
		/// An additional property of the Item struct that may be important to the 
		/// implementation of the EditItem method is the Publish property.  This is 
		/// set to true when the item should be published.  The default setting of 
		/// false denotes that the item may be saved as a draft.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public bool EditItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{
			// Now that we have the BlogID, we can authorize this edit
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, portalSettings.PortalId.ToString(),
										   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			ExtractSummaryFromExtendedContent(ref item);

			// Replace the URL for the metaPost attribution image with one that 
			// will work with the Text/HTML module
			item.Content = Regex.Replace(item.Content, @"/m\.gif", "/m.gif?://");
			item.Content = Regex.Replace(item.Content, @"(?<firstpart>ca0c21fbdc85f6a1597417732d450607\.ashx[^""|>]*)", "$1&x=://");

            UpdateHtmlText(Convert.ToInt32(item.ItemId), item.Title, HttpUtility.HtmlEncode(item.Content), HttpUtility.HtmlEncode(item.Summary), userInfo.UserID, item.Publish, portalSettings.PortalId);

			MetaPostServices.SaveItemImages(Convert.ToInt32(item.ItemId), images, ProviderKey, portalSettings, userInfo.UserID);
			
			ModuleController moduleController = new ModuleController();
			ModuleInfo moduleInfo = moduleController.GetModule(Convert.ToInt32(item.ItemId), Null.NullInteger, false);

			MetaPostServices.RefreshCache(moduleInfo, moduleController);

			// Set page redirect so user will be taken to their page after edit.
			MetaPostServices.SetTempInstallUrl(ProviderKey, Globals.NavigateURL(moduleInfo.TabID));

			return true;
		}

		/// <summary>
		/// DeleteItem is used to delete either a page or a post.  The difference between the two is noted 
		/// in the itemType parameter which is an enumeration set to either Page or Post.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public bool DeleteItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{

			// Now that we have the BlogID, we can authorize this delete
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, portalSettings.PortalId.ToString(),
										   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			// Check to see if a temporary style post was made and needs to be restored.
			string styleId = string.Empty;
			string styleText = string.Empty;
			string styleTitle = string.Empty;

			try
			{
				styleId = MetaPostServices.GetTempStyleValue(userInfo.UserID, "styleId");
				styleText = MetaPostServices.GetTempStyleValue(userInfo.UserID, "content");
				styleTitle = MetaPostServices.GetTempStyleValue(userInfo.UserID, "title");
				
				// Check to make sure the styleText isn't null or empty
				if (string.IsNullOrEmpty(styleText)) styleText = "";
			} catch {} // Ignore any failures.

			if (!string.IsNullOrEmpty(styleId))
			{
				try
				{
					// We will simply restore the text from the old version by retrieving it and 
					ProviderStructs.HtmlInfoStruct htmlInfo = GetHtmlText(Convert.ToInt32(styleId));
					UpdateHtmlText(Convert.ToInt32(styleId), styleTitle, styleText,
                                   HttpUtility.HtmlEncode(htmlInfo.DesktopSummary), htmlInfo.CreatedByUser, true, portalSettings.PortalId);
					
				} catch {} // Ignore failure.
			}
			else
			{
				throw new MetaPostException("FeatureNotImplemented",
				                            "This feature is currently not implemented.");
			}

			return true;
		}

		# endregion

		# region Category Related Procedures

		/// <summary>
		/// GetCategories retrieves a list of categories for a particular module.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public ItemCategoryInfo[] GetCategories(string moduleLevelId, UserInfo userInfo,
												PortalSettings portalSettings)
		{
			ItemCategoryInfo[] categories = null;

			//throw new MetaPostException("FeatureNotImplemented", "This feature is currently not implemented.");

			return categories;
		}

		public bool SetItemCategories(string itemId, ItemCategory[] itemCategories, UserInfo userInfo,
		                        PortalSettings portalSettings)
		{
			// Not implemented for this provider.
			return true;
		}

		public ItemCategory[] GetItemCategories(string itemId, UserInfo userInfo,
		                                        PortalSettings portalSettings)
		{
			// Not implemented for this provider.
			return null;
		}

		/// <summary>
		/// Used to add a new category for modules which support this feature.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public int NewCategory(string moduleLevelId, NewItemCategory category, UserInfo userInfo, PortalSettings portalSettings)
		{
			int categoryId = 0;
			// Check first to see if the user should have the ability to add Categories

			ModuleController moduleController = new ModuleController();
			//ModuleInfo moduleInfo =
			//    moduleController.getm(portalSettings.PortalId, moduleName);
			//bool bHasAdminRights = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles);
			//Dim blnHasModuleEditPermissions As Boolean = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles)

			return categoryId;
		}

		# endregion

		#endregion

		# region Private Procedures Specific to Text/HTML Module

		public void AddHtmlText(int moduleId, string desktopHtml, string desktopSummary, int userId, bool isPublished, int portalId)
		{
            decimal dnnVersion = MetaPostServices.GetDnnVersion();

            if (dnnVersion < 5.01m)
            {
                object[] methodParams = { moduleId, desktopHtml, desktopSummary, userId };
                DataProvider.Instance().ExecuteNonQuery("AddHtmlText", methodParams);
            }
            else
            {

                int stateId = GetStateId(isPublished, moduleId, portalId);

                int history = 5; // This is hardcoded for now.  Will change as we get more information about how
                                 // this property is managed.  Appears to be hard coded in the 05.01.00 release.

                object[] methodParams = { moduleId, desktopHtml, stateId, isPublished, userId, history };
                DataProvider.Instance().ExecuteNonQuery("AddHtmlText", methodParams);
            }
		}

		private void ExtractSummaryFromExtendedContent(ref Item item)
		{
			if (!string.IsNullOrEmpty(item.ExtendedContent))
			{
				// Extract the summary from the excerpt
				item.Summary = item.Content;
				item.Content = item.ExtendedContent;
			}
		}

		public ProviderStructs.HtmlInfoStruct GetHtmlText(int moduleId)
		{
			ProviderStructs.HtmlInfoStruct htmlInfo = new ProviderStructs.HtmlInfoStruct();
			object[] methodParams = { moduleId };
            // Check version of DNN
            decimal dnnVersion = MetaPostServices.GetDnnVersion();

            if (dnnVersion >= 5.01m)
            {
                using (IDataReader dr = DataProvider.Instance().ExecuteReader("itcMetaPost_GetHtmlText", moduleId))
                {
                    while (dr.Read())
                    {
                        htmlInfo.ModuleId = dr.GetInt32(dr.GetOrdinal("ModuleId"));
                        htmlInfo.DesktopHtml = dr.GetString(dr.GetOrdinal("Content"));
                        htmlInfo.DesktopSummary = string.Empty;
                        htmlInfo.CreatedByUser = dr.GetInt32(dr.GetOrdinal("CreatedByUserId"));
                        htmlInfo.CreatedDate = dr.GetDateTime(dr.GetOrdinal("CreatedOnDate"));
                    }
                }
            }
            else
            {
                using (IDataReader dr = DataProvider.Instance().ExecuteReader("GetHtmlText", moduleId))
                {
                    while (dr.Read())
                    {
                        htmlInfo.ModuleId = dr.GetInt32(dr.GetOrdinal("ModuleId"));
                        htmlInfo.DesktopHtml = dr.GetString(dr.GetOrdinal("DesktopHtml"));
                        htmlInfo.DesktopSummary = (!dr.IsDBNull(dr.GetOrdinal("DesktopSummary")))
                            ? dr.GetString(dr.GetOrdinal("DesktopSummary"))
                            : "";
                        htmlInfo.CreatedByUser = dr.GetInt32(dr.GetOrdinal("CreatedByUser"));
                        htmlInfo.CreatedDate = dr.GetDateTime(dr.GetOrdinal("CreatedDate"));
                    }
                }
            }

            // Next, retrieve the title using the module controller
            ModuleController moduleController = new ModuleController();
            ModuleInfo moduleInfo = moduleController.GetModule(moduleId, Null.NullInteger);
            htmlInfo.Title = moduleInfo.ModuleTitle;

			return htmlInfo;
		}

		public void UpdateHtmlText(int moduleId, string title, string desktopHtml, string desktopSummary, int userID, bool isPublished, int portalId)
		{
            
            decimal dnnVersion = MetaPostServices.GetDnnVersion();

            if (dnnVersion < 5.01m)
            {
                object[] methodParams = { moduleId, desktopHtml, desktopSummary, userID };
                // Check to see if we need to add the text/html entry
                ProviderStructs.HtmlInfoStruct htmlInfo = GetHtmlText(moduleId);
                if (htmlInfo.ModuleId != 0)
                {
                    DataProvider.Instance().ExecuteNonQuery("UpdateHtmlText", methodParams);
                }
                else
                {
                    DataProvider.Instance().ExecuteNonQuery("AddHtmlText", methodParams);
                }
            }
            else if (dnnVersion < 6.01m) // This is the newer version of DNN where workflow and versioning was added.
            {
                int draftItemId = GetDraftItemID(moduleId);
                if (isPublished == false && draftItemId != -1)
                {

                    int stateId = GetStateId(isPublished, moduleId, portalId);

                    object[] methodParams = { draftItemId, desktopHtml, stateId, isPublished, userID };
                    DataProvider.Instance().ExecuteNonQuery("UpdateHtmlText", methodParams);
                }
                else
                {
                    AddHtmlText(moduleId, desktopHtml, desktopSummary, userID, isPublished, portalId);
                }
            } // This is after 6.1.1 where the implementation was changed yet again.
            else
            {
                int draftItemId = GetDraftItemID(moduleId);
                
                HtmlTextController htc = new HtmlTextController();
                HtmlTextInfo textInfo = htc.GetHtmlText(moduleId, draftItemId);
                int stateId = GetStateId(isPublished, textInfo);

                textInfo.Content = desktopHtml;
                textInfo.StateID = stateId;
                textInfo.IsPublished = isPublished;
                textInfo.ItemID = draftItemId;

                htc.UpdateHtmlText(textInfo, 100);

            }
                
            // Also need to update the Module Title in case it changed.
            // Next, retrieve the title using the module controller
            ModuleController moduleController = new ModuleController();
            ModuleInfo moduleInfo = moduleController.GetModule(moduleId, Null.NullInteger);
            moduleInfo.ModuleTitle = HttpUtility.HtmlDecode(title);
            moduleController.UpdateModule(moduleInfo);
		}

        private int GetDraftItemID(int moduleId)
        {
            int draftItemId = -1;
            using (IDataReader dr = DataProvider.Instance().ExecuteReader("itcMetaPost_GetHtmlText", moduleId))
            {
                while (dr.Read())
                {
                    int stateId = dr.GetInt32(dr.GetOrdinal("StateID"));
                    /*if (stateId == 2)*/ draftItemId = dr.GetInt32(dr.GetOrdinal("ItemID"));
                }
            }
            return draftItemId;
        }

        private static int GetStateId(bool isPublished, HtmlTextInfo textInfo)
        {
            int stateId;
            
            if (isPublished == false)
            {
                stateId = 2;
            }
            else if (textInfo.WorkflowID == 1)
            {
                stateId = 1;
            }
            else
            {
                stateId = 3;
            }
            return stateId;
        }

        private static int GetStateId(bool isPublished, int moduleId, int portalId)
        {
            int stateId;
            var mc = new ModuleController();
            ModuleInfo moduleInfo = mc.GetModule(moduleId, Null.NullInteger, false);
            var tabModuleId = moduleInfo.TabModuleID;

            var moduleSettings = mc.GetTabModuleSettings(tabModuleId); //PortalSettings.GetTabModuleSettings(moduleId);
            string siteWorkflowId;
            PortalController.GetPortalSettingsDictionary(portalId).TryGetValue("WorkflowID", out siteWorkflowId); //PortalSettings.GetSiteSetting(portalId, "WorkflowID");

            var workflowId = moduleSettings["WorkflowID"] as string;
            var wflId = 0;
            if (!string.IsNullOrEmpty(workflowId)) int.TryParse(workflowId, out wflId);


            if (isPublished == false)
            {
                stateId = 2;
            }
            else if (!string.IsNullOrEmpty(siteWorkflowId) && siteWorkflowId == "1" && wflId != 2)
            {
                stateId = 1;
            }
            else if (wflId == 1)
            {
                stateId = 1;
            }
            else
            {
                stateId = 3;
            }
            return stateId;
        }

		# endregion

	}
}